package com.njxxted.activiti.modules.process.extend.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Maps;
import com.njxxted.activiti.common.constant.Constant;
import com.njxxted.activiti.common.util.PageUtil;
import com.njxxted.activiti.common.util.StringUtils;
import com.njxxted.activiti.common.util.UserUtil;
import com.njxxted.activiti.modules.api.entity.UserDto;
import com.njxxted.activiti.modules.process.defintion.dao.ActDefinitionDao;
import com.njxxted.activiti.modules.process.extend.dao.ExtendActCopyDao;
import com.njxxted.activiti.modules.process.extend.dao.ExtendActInstanceDao;
import com.njxxted.activiti.modules.process.extend.entity.ActProcessConfigEntity;
import com.njxxted.activiti.modules.process.extend.entity.ExtendActCopyEntity;
import com.njxxted.activiti.modules.process.extend.entity.ExtendActInstanceEntity;
import com.njxxted.activiti.modules.process.extend.entity.req.ExtendActInstanceReqEntity;
import com.njxxted.activiti.modules.process.extend.service.ExtendActInstanceService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.identity.Group;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.ibatis.jdbc.SQL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.stream.Collectors;

/**
 * 描述：工作流扩展表-流程实例表 service
 * <p>
 * 作者：HuTongFu
 * 邮箱：hu_tongfu@163.com
 * 时间：2019-08-10 17:14:48
 */
@Service("extActPInstanceService")
public class ExtendActInstanceServiceImpl implements ExtendActInstanceService {

    protected Logger logger = LoggerFactory.getLogger(this.getClass());

    @Resource
    private ExtendActInstanceDao extActPInstanceDao;
    @Resource
    private ExtendActCopyDao extendActCopyDao;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private TaskService taskService;

    @Override
    public ExtendActInstanceEntity queryObject(String id) {
        return extActPInstanceDao.queryObject(id);
    }

    @Transactional(readOnly = true)
    @Override
    public PageUtil<ExtendActInstanceEntity> getTaskForMeList(String userId, int pageNum, int pageSize) {
        UserDto currUser = UserUtil.getUserFromRedis();

        //定义一个集合存储属于当前登录用户的流程实例id
        CopyOnWriteArraySet<String> instanceIdSet = new CopyOnWriteArraySet<>();

        //查询出所有待办（包含草稿）的配置信息,过滤流程当前节点所配置的人员信息是包含当前登录用户的流程
        List<ActProcessConfigEntity> configs = extActPInstanceDao.getProcessAssignConfig();

        configs.parallelStream().forEachOrdered(config -> {
            StringBuilder conditionStr = new StringBuilder();
            config.getConfigs().parallelStream().forEachOrdered(setting -> {
                String configValue = setting.getConfigValue();
                String otherValue = setting.getOtherValue();
                switch (setting.getConfigType()) {
                    case Constant.Flow.ASSIGN_USER:
                        conditionStr.append(configValue.equals(currUser.getId())).append(otherValue);
                        break;
                    case Constant.Flow.ASSIGN_DEPART:
                        conditionStr.append(configValue.equals(currUser.getDepartId())).append(otherValue);
                        break;
                    case Constant.Flow.ASSIGN_ROLE:
                        conditionStr.append(configValue.equals(currUser.getRoleId())).append(otherValue);
                        break;
                }
            });
            String replace = conditionStr.toString().replace("and", " && ")
                    .replace("or", " || ");
            if (StringUtils.isTrue(replace)) {
                instanceIdSet.add(config.getInstanceId());
            }
        });

        String appendSql;
        String startUserId = currUser.getId();
        if (instanceIdSet.size() > 0) {
            String instanceId = instanceIdSet.parallelStream().collect(Collectors.joining("','"));
            appendSql = getSql(instanceId, startUserId, true);
        } else {
            appendSql = getSql(null, startUserId, false);
        }

        PageHelper.startPage(pageNum, pageSize);
        List<ExtendActInstanceEntity> extActInstanceList = extActPInstanceDao.queryListByCondition(appendSql);
        PageInfo<ExtendActInstanceEntity> pageInfo = new PageInfo<>(extActInstanceList);
        return new PageUtil<>(extActInstanceList, (int) pageInfo.getTotal(), pageInfo.getPageSize(), pageInfo.getPageNum());
    }

    private String getSql(final String instanceId, final String startUserId, boolean flag) {
        return new SQL() {{
            String[] cloumns = {
                    "api.id", "api.instance_id", "api.process_def_id", "api.process_key", "api.business_id",
                    "api.name", "art.TASK_DEF_KEY_ AS currNodeDefKey", "api.curr_node_name", "api.curr_node_id",
                    "api.pre_node_id", "api.recently_do_time", "api.status", "api.start_node_key",
                    "api.add_date", "api.start_user_id", "u.last_ AS startUserName", "art.DUE_DATE_ AS deadline"};
            SELECT(cloumns);
            FROM("t_extend_act_process_instance api");
            LEFT_OUTER_JOIN("act_id_user u on api.start_user_id = u.id_");
            LEFT_OUTER_JOIN("act_ru_task art on art.PROC_INST_ID_ = api.instance_id");
            if (flag) {
                WHERE("api.instance_id in ('" + instanceId + "')");
                OR().WHERE("api.start_user_id = '" + startUserId + "'", "api.status not in ('0', '6','7')");
                ORDER_BY("api.recently_do_time desc");
            } else {
                WHERE("api.start_user_id = '" + startUserId + "'", "api.status != '0'");
                ORDER_BY("api.recently_do_time desc");
            }
        }}.toString();
    }

    @Transactional(readOnly = true)
    @Override
    public PageUtil<ExtendActInstanceEntity> queryMyHasBeenDoneList(ExtendActInstanceReqEntity param) {
        if (Objects.isNull(param)) {
            return null;
        }
        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        List<ExtendActInstanceEntity> list = extActPInstanceDao.getMyHasBeenDoneList(param);
        //过滤掉草稿的流程
//        List<ExtendActInstanceEntity> collect = list.parallelStream()
//                .filter(obj -> !Constant.Flow.TASK_DRAFT.equals(obj.getStatus())).collect(Collectors.toList());
        PageInfo<ExtendActInstanceEntity> pageInfo = new PageInfo<>(list);
        return new PageUtil<>(list, pageInfo.getTotal(), param.getPageSize(), param.getPageNum());
    }

    @Override
    public PageUtil<ExtendActInstanceEntity> getMyStartedList(ExtendActInstanceReqEntity param) {
        if (Objects.isNull(param)) {
            return null;
        }
        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        List<ExtendActInstanceEntity> instances = extActPInstanceDao.getMyStartedList(param);
        PageInfo<ExtendActInstanceEntity> pageInfo = new PageInfo<>(instances);
        return new PageUtil<>(instances, pageInfo.getTotal(), pageInfo.getPageSize(), pageInfo.getPageNum());
    }

    @Override
    public PageUtil<ExtendActInstanceEntity> getCopy2MeList(ExtendActInstanceReqEntity param) {
        if (Objects.isNull(param)) {
            return null;
        }
        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        List<ExtendActInstanceEntity> instances = extActPInstanceDao.queryCopyList(param);
        PageInfo<ExtendActInstanceEntity> pageInfo = new PageInfo<>(instances);
        return new PageUtil<>(instances, pageInfo.getTotal(), pageInfo.getPageSize(), pageInfo.getPageNum());
    }

    @Override
    public void updCopyStatus(ExtendActCopyEntity param) {
        logger.debug("流程扩展实例id：{},当前节点id：{}", param.getInstanceId(), param.getTaskId());
        param.setUserId(UserUtil.getUserFromRedis().getId());
        param.setTaskId(null);
        extendActCopyDao.update(param);
    }

    @Override
    public List<ExtendActInstanceEntity> queryListByBean(ExtendActInstanceEntity param) {
        return extActPInstanceDao.queryListByBean(param);
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    @Override
    public int save(ExtendActInstanceEntity extActPInstance) {
        extActPInstance.setId(StringUtils.uuidGenerator());
        if (Objects.isNull(extActPInstance.getStatus())) {
            extActPInstance.setStatus(Constant.Flow.TASK_AGREE);
        }

        //跟流程实例id查询最新创建的任务
        if (extActPInstance.getInstanceId() != null) {
            List<Task> taskList = taskService.createTaskQuery().processInstanceId(extActPInstance.getInstanceId())
                    .orderByTaskCreateTime().desc().list();

            if (taskList.size() > 0) {
                Task task = taskList.get(0);
                extActPInstance.setCurrNodeId(task.getId());
                extActPInstance.setCurrNodeName(task.getName());
                extActPInstance.setRecentlyDoTime(new Date());
                extActPInstance.setStartNodeKey(task.getTaskDefinitionKey());
            }
        }
        return extActPInstanceDao.save(extActPInstance);
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    @Override
    public int saveDraft(ExtendActInstanceEntity extActPInstance) {
        extActPInstance.setId(StringUtils.uuidGenerator());
        extActPInstance.setStatus(Constant.Flow.TASK_DRAFT);
        extActPInstance.setName(extActPInstance.getName());
        return extActPInstanceDao.save(extActPInstance);
    }

    @Override
    public int update(ExtendActInstanceEntity extActPInstance) {
        return extActPInstanceDao.update(extActPInstance);
    }

    @Override
    public int delete(String id) {
        return extActPInstanceDao.delete(id);
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public int deleteBatch(String[] ids) {
        return extActPInstanceDao.deleteBatch(ids);
    }

    @Override
    public Set<Map<String, Object>> getSelectData(ExtendActInstanceReqEntity param) {
        logger.debug("查询参数：{}", param);
        if (Objects.isNull(param)) {
            return null;
        }
        param.setPageSize(100);
        List<ExtendActInstanceEntity> extInstanceList = extActPInstanceDao.getExtInstanceList(param);
        CopyOnWriteArraySet<Map<String, Object>> res = new CopyOnWriteArraySet<>();
        extInstanceList.parallelStream().forEach(extendActInstance -> {
            Map<String, Object> map = Maps.newHashMap();
            map.put("name", extendActInstance.getName());
            res.add(map);
        });
        return res;
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class, readOnly = true)
    @Override
    public Map<String, Integer> queryMyHasBeenDoneCount(ExtendActInstanceReqEntity param) {
        Map<String, Integer> map = Maps.newHashMap();
        //1.办理中
        param.setStatus("1");
        map.put("doing", extActPInstanceDao.getMyHasBeenDoneCount(param));
        //2.挂起
        param.setStatus("4");
        map.put("suspend", extActPInstanceDao.getMyHasBeenDoneCount(param));
        //3.作废
        param.setStatus("6");
        map.put("cancel", extActPInstanceDao.getMyHasBeenDoneCount(param));
        //4.办结
        param.setStatus("7");
        map.put("finish", extActPInstanceDao.getMyHasBeenDoneCount(param));
        return map;
    }

    @Override
    public PageUtil<ExtendActInstanceEntity> getMyDraftList(ExtendActInstanceReqEntity param) {
        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        List<ExtendActInstanceEntity> list = extActPInstanceDao.getMyDraftList(param);
        PageInfo<ExtendActInstanceEntity> pageInfo = new PageInfo<>(list);
        return new PageUtil<>(list, pageInfo.getTotal(), param.getPageSize(), param.getPageNum());
    }

}
